package com.example.demo.utils;

import java.nio.charset.StandardCharsets;

public class Base64Util {
    //用一个char数组封装base64码
    private static final char[] toBase64 = {
            'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
            'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
            'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
            'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
            '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
    };

    /**
     * 转换为base64码
     *
     * @param tar
     * @return
     */
    public static String switchToBase64(String tar) {
        byte[] bytes = tar.getBytes();
        //补零
        //剩下几个字节 yu 可能等于0 1 2
        int yu = bytes.length % 3;
        int count = bytes.length / 3;

        StringBuilder res = new StringBuilder();

        for (int i = 1; i <= count; i++) {
            int index = (i - 1) * 3;
            //每三个byte24转换为4个6bit为一组的Base64二进制码
            int base = transform(bytes[index], bytes[index + 1], bytes[index + 2]);
            //取最左边的 0X3F 表示6个bit位
            int left = (base >>> 18) & 0X3F;
            int middleLeft = (base >>> 12) & 0X3F;
            int middleRight = (base >>> 6) & 0X3F;
            int right = base & 0X3F;

            // 1  0
            // 2  3
            // 3  6
            res.append(toBase64[left]);
            res.append(toBase64[middleLeft]);
            res.append(toBase64[middleRight]);
            res.append(toBase64[right]);
        }

        //处理余数
        /*    5
        int yu = bytes.length % 3;  //
        int count = bytes.length / 3;*/
        //接取剩下的 yu为1或2
        if (yu == 1) {
            byte[] a = new byte[3];
            a[0] = bytes[3 * count];
            a[1] = a[2] = 0;
            int base2 = transform(a[0], a[1], a[2]);
            //取每一个6位
            int left = (base2 >>> 18) & 0X3F;
            int middleLeft = (base2 >>> 12) & 0X3F;

            res.append(toBase64[left]);
            res.append(toBase64[middleLeft]);
            res.append('=');
            res.append('=');
        }
        if (yu == 2) {
            byte[] a = new byte[3];
            a[0] = bytes[3 * count];
            a[1] = bytes[3 * count + 1];
            a[2] = 0;
            int base2 = transform(a[0], a[1], a[2]);
            //取每一个6位
            int left = (base2 >>> 18) & 0X3F;
            int middleLeft = (base2 >>> 12) & 0X3F;
            int middleRight = (base2 >>> 6) & 0X3F;

            res.append(toBase64[left]);
            res.append(toBase64[middleLeft]);
            res.append(toBase64[middleRight]);
            res.append('=');
        }
        return res.toString();
    }

    /**
     * 解码方法
     * @param str 字符串
     * @return 返回解码后的字符串
     */
    public static String reversalBase64(String str) {
        //记录=的数量
        int count = 0;
        //arr下标指针
        int index = 0;
        //bytes下标指针
        int indexs = 0;

        String result;
        try {

            //遍历字符串得到=的数量
            for (int i = 0; i < str.length(); i++) {
                if (str.charAt(i) == '=') {
                    count++;
                }
            }
            //new一个arr数组用来存放非=的字符串
            int length = str.length() - count;
            int[] arr = new int[length];
            //得到arr数组的值所对应的char数组的下标
            for (int i = 0; i < length; i++) {
                for (int j = 0; j < toBase64.length; j++) {
                    if (str.charAt(i) == toBase64[j]) {
                        arr[i] = j;
                    }
                }
            }
            //new一个bytes数组用来存放解码后的字符串的每一个字符
            byte[] bytes = new byte[str.length() / 4 * 3 - count];
            while ((length / 4) > 0) {
                //当arr数组长度大于等于4时，就将arr[index]，arr[index + 1]，arr[index + 2]，arr[index + 3]
                // （每一个arr[]都由6位二进制数组成）拼接成24位二进制数
                int v = (arr[index] & 0x3F) << 18 | (arr[index + 1] & 0x3F) << 12 | (arr[index + 2] & 0x3F) << 6 | (arr[index + 3] & 0x3F);
                //每8位为一组转化成byte型，并赋值给bytes
                //右移16位，取8位
                bytes[indexs] = (byte) (v >>> 16 & 0xFF);
                //右移8位，取8位
                bytes[indexs + 1] = (byte) (v >>> 8 & 0xFF);
                //取8位
                bytes[indexs + 2] = (byte) (v & 0xFF);
                //bytes下标指针加3
                indexs += 3;
                //arr下标指针加4
                index += 4;
                //arr数组长度减4
                length -= 4;
                //如果还满足(length / 4) > 0，取接下来的4个arr[]进行拼接，不满足则跳出循环
            }

            if (count == 1) {
                //如果存在1个=
                //将arr[index]，arr[index + 1]，arr[index + 2]拼接成18位二进制数
                int v = (arr[index] & 0x3F) << 12 | (arr[index + 1] & 0x3F) << 6 | (arr[index + 2] & 0x3F);
                //每8位为一组转化成byte型，并赋值给bytes
                //右移10位，取8位
                bytes[indexs] = (byte) (v >>> 10 & 0xFF);
                //右移2位，取8位
                bytes[indexs + 1] = (byte) (v >>> 2 & 0xFF);
            } else if (count == 2) {
                //如果存在2个=
                //将arr[index]，arr[index + 1]拼接成12位二进制数
                int v = (arr[index] & 0x3F) << 6 | (arr[index + 1] & 0x3F);
                //每8位为一组转化成byte型，并赋值给bytes
                //右移4位，取8位
                bytes[indexs] = (byte) (v >>> 4 & 0xFF);
            }
            //将bytes数组中存的字符转换成String类型
             result = new String(bytes, StandardCharsets.UTF_8);
        }catch (Exception e){
            return "Token错误";
        }
        return result;
    }


    /**
     * 将三个byte转变为int
     *
     * @param aByte
     * @param aByte1
     * @param aByte2
     * @return 三个byte组成的int  注意判断int的正负
     */
    private static int transform(byte aByte, byte aByte1, byte aByte2) {
        //int a = aByte * 100000000 + aByte1 * 10000 + aByte2;

        //1000 0000  |或   &与 1 0 -> 0
        //java会先变成int 4个8位  隐式转换
        //
        return ((aByte & 0xFF) << 16) | ((aByte1 & 0xFF) << 8) | (aByte2 & 0xFF);
    }




}
